home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / ADA / GNAT / !gcc / adainc / 2 / adb / a-tasatt < prev    next >
Text File  |  1996-02-12  |  28KB  |  769 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                  A D A . T A S K _ A T T R I B U T E S                   --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.5 $                              --
  10. --                                                                          --
  11. --      Copyright (C) 1991,1992,1993,1994,1995 Florida State University     --
  12. --                                                                          --
  13. -- GNARL is free software; you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion. GNARL is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNARL; see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNARL was developed by the GNARL team at Florida State University. It is --
  32. -- now maintained by Ada Core Technologies Inc. in cooperation with Florida --
  33. -- State University (http://www.gnat.com).                                  --
  34. --                                                                          --
  35. ------------------------------------------------------------------------------
  36.  
  37. --  The following notes are provided in case someone decides the
  38. --  implementation of this package is too complicated, or too slow.
  39. --  Please read this before making any "simplifications".
  40.  
  41. --  Correct implementation of this package is more difficult than one
  42. --  might expect. After considering (and coding) several alternatives,
  43. --  we settled on the present compromise. Things we do not like about
  44. --  this implementation include:
  45.  
  46. --  -  It is vulnerable to bad Task_ID values, to the extent of
  47. --     possibly trashing memory and crashing the runtime system.
  48.  
  49. --  -  It requires dynamic storage allocation for each new attribute value,
  50. --     except for types that happen to be the same size as System.Address,
  51. --     or shorter.
  52.  
  53. --  -  Instantiations at other than the library level rely on being able to
  54. --     do down-level calls to a procedure declared in the generic package body.
  55. --     This makes it potentially vulnerable to compiler changes.
  56.  
  57. --  The main implementation issue here is that the connection from
  58. --  task to attribute is a potential source of dangling references.
  59.  
  60. --  When a task goes away, we want to be able to recover all the storage
  61. --  associated with its attributes. The Ada mechanism for this is
  62. --  finalization, via controlled attribute types. For this reason,
  63. --  the ARM requires finalization of attribute values when the
  64. --  associated task terminates.
  65.  
  66. --  This finalization must be triggered by the tasking runtime system,
  67. --  during termination of the task. Given the active set of instantiations
  68. --  of Ada.Task_Attributes is dynamic, the number and types of attributes
  69. --  belonging to a task will not be known until the task actually terminates.
  70. --  Some of these types may be controlled and some may not. The RTS must find
  71. --  some way to determine which of these attributes need finalization, and
  72. --  invoke the appropriate finalization on them.
  73.  
  74. --  One way this might be done is to create a special finalization chain
  75. --  for each task, similar to the finalization chain that is used for
  76. --  controlled objects within the task. This would differ from the usual
  77. --  finalization chain in that it would not have a LIFO structure, since
  78. --  attributes may be added to a task at any time during its lifetime.
  79. --  This might be the right way to go for the longer term, but at present
  80. --  this approach is not open, since GNAT does not provide such special
  81. --  finalization support.
  82.  
  83. --  Lacking special compiler support, the RTS is limited to the
  84. --  normal ways an application invokes finalization, i.e.
  85.  
  86. --  a) Explicit call to the procedure Finalize, if we know the type
  87. --     has this operation defined on it. This is not sufficient, since
  88. --     we have no way of determining whether a given generic formal
  89. --     Attribute type is controlled, and no visibility of the associated
  90. --     Finalize procedure, in the generic body.
  91.  
  92. --  b) Leaving the scope of a local object of a controlled type.
  93. --     This does not help, since the lifetime of an instantiation of
  94. --     Ada.Task_Attributes does not correspond to the lifetimes of the
  95. --     various tasks which may have that attribute.
  96.  
  97. --  c) Assignment of another value to the object. This would not help,
  98. --     since we then have to finalize the new value of the object.
  99.  
  100. --  d) Unchecked deallocation of an object of a controlled type.
  101. --     This seems to be the only mechanism available to the runtime
  102. --     system for finalization of task attributes.
  103.  
  104. --  We considered two ways of using unchecked deallocation, both based
  105. --  on a linked list of that would hang from the task control block.
  106.  
  107. --  In the first approach the objects on the attribute list are all derived
  108. --  from one controlled type, say T, and are linked using an access type to
  109. --  T'Class. The runtime system has an Unchecked_Deallocation for T'Class
  110. --  with access type T'Class, and uses this to deallocate and finalize all
  111. --  the items in the list. The limitation of this approach is that each
  112. --  instantiation of the package Ada.Task_Attributes derives a new record
  113. --  extension of T, and since T is controlled (RM 3.9.1 (3)), instantiation
  114. --  is only allowed at the library level.
  115.  
  116. --  In the second approach the objects on the attribute list are of
  117. --  unrelated but structurally similar types. Unchecked conversion is
  118. --  used to circument Ada type checking. Each attribute-storage node
  119. --  contains not only the attribute value and a link for chaining, but
  120. --  also a pointer to a descriptor for the corresponding instantiation
  121. --  of Task_Attributes. The instantiation-descriptor contains a
  122. --  pointer to a procedure that can do the correct deallocation and
  123. --  finalization for that type of attribute. On task termination, the
  124. --  runtime system uses the pointer to call the appropriate deallocator.
  125.  
  126. --  While this gets around the limitation that instantations be at
  127. --  the library level, it relies on an implementation feature that
  128. --  may not always be safe, i.e. that it is safe to call the
  129. --  Deallocate procedure for an instantiation of Ada.Task_Attributes
  130. --  that no longer exists. In general, it seems this might result in
  131. --  dangling references.
  132.  
  133. --  Another problem with instantiations deeper than the library level
  134. --  is that there is risk of storage leakage, or dangling references
  135. --  to reused storage. That is, if an instantiation of Ada.Task_Attributes
  136. --  is made within a procedure, what happens to the storage allocated for
  137. --  attributes, when the procedure call returns?  Apparently (RM 7.6.1 (4))
  138. --  any such objects must be finalized, since they will no longer be
  139. --  accessible, and in general one would expect that the storage they occupy
  140. --  would be recovered for later reuse. (If not, we would have a case of
  141. --  storage leakage.)  Assuming the storage is recovered and later reused,
  142. --  we have potentially dangerous dangling references. When the procedure
  143. --  containing the instantiation of Ada.Task_Attributes returns, there
  144. --  may still be unterminated tasks with associated attribute values for
  145. --  that instantiation. When such tasks eventually terminate, the RTS
  146. --  will attempt to call the Deallocate procedure on them. If the
  147. --  corresponding storage has already been deallocated, when the master
  148. --  of the access type was left, we have a potential disaster. This
  149. --  disaster is compounded since the pointer to Deallocate is probably
  150. --  through a "trampoline" which will also have been destroyed.
  151.  
  152. --  For this reason, we arrange to remove all dangling references
  153. --  before leaving the scope of an instantiation. This is ugly, since
  154. --  it requires traversing the list of all tasks, but it is no more ugly
  155. --  than a similar traversal that we must do at the point of instantiation
  156. --  in order to initialize the attributes of all tasks. At least we only
  157. --  need to do these traversals if the type is controlled.
  158.  
  159. --  We chose to defer allocation of storage for attributes until the
  160. --  Reference function is called or the attribute is first set to a value
  161. --  different from the default initial one. This allows a potential
  162. --  savings in allocation, for attributes that are not used by all tasks.
  163.  
  164. --  For efficiency, we reserve space in the TCB for a fixed number of
  165. --  direct-access attributes. These are required to be of a size that
  166. --  fits in the space of an object of type System.Address. Because
  167. --  we must use unchecked bitwise copy operations on these values, they
  168. --  cannot be of a controlled type, but that is covered automatically
  169. --  since controlled objects are too large to fit in the spaces.
  170.  
  171. --  We originally deferred the initialization of these direct-access
  172. --  attributes, just as we do for the indirect-access attributes, and
  173. --  used a per-task bit vector to keep track of which attributes were
  174. --  currently defined for that task. We found that the overhead of
  175. --  maintaining this bit-vector seriously slowed down access to the
  176. --  attributes, and made the fetch operation non-atomic, so that even
  177. --  to read an attribute value required locking the TCB. Therefore,
  178. --  we now initialize such attributes for all existing tasks at the time
  179. --  of the attribute instantiation, and initialize existing attributes
  180. --  for each new task at the time it is created.
  181.  
  182. --  The latter initialization requires a list of all the instantiation
  183. --  descriptors.  Updates to this list, as well as the bit-vector that
  184. --  is used to reserve slots for attributes in the TCB, require mutual
  185. --  exclusion. That is provided by the lock System.Tasking.Task_-
  186. --  Attributes.All_Attrs_L.
  187.  
  188. --  One special problem that added complexity to the design is that
  189. --  the per-task list of indirect attributes contains objects of
  190. --  different types. We use unchecked pointer conversion to link
  191. --  these nodes together and access them, but the records may not have
  192. --  identical internal structure. Initially, we thought it would be
  193. --  enough to allocate all the common components of the records at the
  194. --  front of each record, so that their positions would correspond.
  195. --  Unfortunately, GNAT adds "dope" information at the front of a record,
  196. --  if the record contains any controlled-type components.
  197. --
  198. --  This means that the offset of the fields we use to link the nodes is
  199. --  at different positions on nodes of different types. To get around this,
  200. --  each attribute storage record consists of a core node and wrapper.
  201. --  The core nodes are all of the same type, and it is these that are
  202. --  linked together and generally "seen" by the RTS. Each core node
  203. --  contains a pointer to its own wrapper, which is a record that contains
  204. --  the core node along with an attribute value, approximately
  205. --  as follows:
  206.  
  207. --    type Node;
  208. --    type Node_Access is access all Node;
  209. --    type Node_Access;
  210. --    type Access_Wrapper is access all Wrapper;
  211. --    type Node is record
  212. --       Next    : Node_Access;
  213. --       ...
  214. --       Wrapper : Access_Wrapper;
  215. --    end record;
  216. --    type Wrapper is record
  217. --       Noed    : aliased Node;
  218. --       Value   : aliased Attribute;  --  the generic formal type
  219. --    end record;
  220.  
  221. --  Another interesting problem is with the initialization of
  222. --  the instantiation descriptors. Originally, we did this all via
  223. --  the Initialize procedure of the descriptor type and code in the
  224. --  package body. It turned out that the Initialize procedure needed
  225. --  quite a bit of information, including the size of the attribute
  226. --  type, the initial value of the attribute (if it fits in the TCB),
  227. --  and a pointer to the deallocator procedure. These needed to be
  228. --  "passed" in via access discriminants. GNAT was having trouble
  229. --  with access discriminants, so all this work was moved to the
  230. --  package body.
  231.  
  232. with Ada.Finalization;
  233. with System;
  234. with System.Storage_Elements;
  235. with System.Task_Primitives;
  236. with System.Tasking;
  237. with System.Tasking.Initialization;
  238. with System.Tasking.Task_Attributes;
  239. with System.Tasking.Utilities;
  240. with Unchecked_Conversion;
  241. with Unchecked_Deallocation;
  242.  
  243. pragma Elaborate_All (System.Tasking.Task_Attributes);
  244. --  to ensure the initialization of object Local (below) will work
  245.  
  246. package body Ada.Task_Attributes is
  247.  
  248.    use System.Task_Primitives,
  249.        System.Tasking,
  250.        System.Tasking.Initialization,
  251.        System.Tasking.Task_Attributes,
  252.        System.Tasking.Utilities;
  253.  
  254.    use type System.Tasking.Access_Address;
  255.  
  256.    ---------------------------------
  257.    -- Unchecked Conversion Tricks --
  258.    ---------------------------------
  259.  
  260.    --  The following type corresponds to Dummy_Wrapper,
  261.    --  declared in System.Tasking.Task_Attributes.
  262.  
  263.    type Wrapper;
  264.    type Access_Wrapper is access all Wrapper;
  265.  
  266.    function To_Attribute_Handle is new Unchecked_Conversion
  267.      (Access_Address, Attribute_Handle);
  268.    --  for reference to directly addressed task attributes
  269.  
  270.    type Access_Integer_Address is access all
  271.      System.Storage_Elements.Integer_Address;
  272.  
  273.    function To_Attribute_Handle is new Unchecked_Conversion
  274.      (Access_Integer_Address, Attribute_Handle);
  275.    --  for reference to directly addressed task attributes
  276.  
  277.    function To_Access_Address is new Unchecked_Conversion
  278.      (Access_Node, Access_Address);
  279.    --  to store pointer to list of indirect attributes
  280.  
  281.    function To_Access_Node is new Unchecked_Conversion
  282.      (Access_Address, Access_Node);
  283.    --  to fetch pointer to list of indirect attributes
  284.  
  285.    function To_Access_Wrapper is new Unchecked_Conversion
  286.      (Access_Dummy_Wrapper, Access_Wrapper);
  287.    --  to fetch pointer to actual wrapper of attribute node
  288.  
  289.    function To_Access_Dummy_Wrapper is new Unchecked_Conversion
  290.      (Access_Wrapper, Access_Dummy_Wrapper);
  291.    --  to store pointer to actual wrapper of attribute node
  292.  
  293.    function To_Task_ID is new Unchecked_Conversion
  294.      (Task_Identification.Task_Id, Task_ID);
  295.    --  to access TCB of identified task
  296.  
  297.    Null_ID : constant Task_ID := To_Task_ID (Task_Identification.Null_Task_ID);
  298.  
  299.    type Local_Deallocator is
  300.       access procedure (P : in out Access_Node);
  301.    function To_Lib_Level_Deallocator is new Unchecked_Conversion
  302.      (Local_Deallocator, Deallocator);
  303.    --  to defeat accessibility check
  304.  
  305.    ------------------------
  306.    -- Storage Management --
  307.    ------------------------
  308.  
  309.    procedure Deallocate (P : in out Access_Node);
  310.    --  Passed to the RTS via unchecked conversion of a pointer to
  311.    --  permit finalization and deallocation of attribute storage nodes
  312.  
  313.    --------------------------
  314.    -- Instantiation Record --
  315.    --------------------------
  316.  
  317.    Local : aliased Instance;
  318.    --  Initialized in package body
  319.  
  320.    type Wrapper is record
  321.       Noed : aliased Node;
  322.  
  323. --  Gigi abort ???:
  324. --      (To_Access_Dummy_Wrapper (Wrapper'Access), Local'Unchecked_Access);
  325. --      (Access_Dummy_Wrapper' (To_Access_Dummy_Wrapper (Wrapper'Access)),
  326. --          Local'Unchecked_Access);
  327.  
  328.       Value : aliased Attribute := Initial_Value;
  329.       --  The generic formal type, may be controlled
  330.    end record;
  331.  
  332.    procedure Free is
  333.       new Unchecked_Deallocation (Wrapper, Access_Wrapper);
  334.  
  335.    procedure Deallocate (P : in out Access_Node) is
  336.       T : Access_Wrapper := To_Access_Wrapper (P.Wrapper);
  337.  
  338.    begin
  339.       Free (T);
  340.  
  341.    exception
  342.       when others =>
  343.          null;
  344.          pragma Assert (
  345.            System.Tasking.Utilities.Runtime_Assert_Shutdown
  346.            ("Exception in Deallocate"));
  347.    end Deallocate;
  348.  
  349.    ---------------
  350.    -- Reference --
  351.    ---------------
  352.  
  353.    function Reference
  354.      (T    : Task_Identification.Task_Id := Task_Identification.Current_Task)
  355.       return Attribute_Handle
  356.    is
  357.       Lock_Result : Boolean;
  358.       TT          : Task_ID := To_Task_ID (T);
  359.  
  360.    begin
  361.       if TT = Null_ID then
  362.          raise Program_Error;
  363.       end if;
  364.  
  365.       if TT.Stage = Terminated then
  366.          raise Tasking_Error;
  367.       end if;
  368.  
  369.       begin
  370.          Defer_Abortion; Write_Lock (TT.L, Lock_Result);
  371.  
  372.          if Local.Index /= 0 then
  373.             Unlock (TT.L);
  374.             Undefer_Abortion;
  375.             return To_Attribute_Handle
  376.                (TT.Direct_Attributes (Local.Index)'Access);
  377.  
  378.          else
  379.             declare
  380.                P : Access_Node := To_Access_Node (TT.Indirect_Attributes);
  381.                W : Access_Wrapper;
  382.  
  383.             begin
  384.                while P /= null loop
  385. --  Gigi bug: ???
  386. --                  if P.Instance = Local'Unchecked_Access then
  387.  
  388.                   if P.Instance = Access_Instance'(Local'Unchecked_Access) then
  389.                      Unlock (TT.L);
  390.                      Undefer_Abortion;
  391.                      return To_Access_Wrapper (P.Wrapper).Value'Access;
  392.                   end if;
  393.  
  394.                   P := P.Next;
  395.                end loop;
  396.  
  397.                W := new Wrapper'
  398.                  ((null, Local'Unchecked_Access, null), Initial_Value);
  399.  
  400.                P := W.Noed'Unchecked_Access;
  401.                P.Wrapper := To_Access_Dummy_Wrapper (W);
  402.                P.Next := To_Access_Node (TT.Indirect_Attributes);
  403.                TT.Indirect_Attributes := To_Access_Address (P);
  404.                Unlock (TT.L);
  405.                Undefer_Abortion;
  406.                return W.Value'Access;
  407.             end;
  408.          end if;
  409.  
  410.          pragma Assert (
  411.             System.Tasking.Utilities.Runtime_Assert_Shutdown
  412.             ("Should never get here in Reference"));
  413.          return null;
  414.  
  415.       exception
  416.          when others =>
  417.             Unlock (TT.L);
  418.             Undefer_Abortion;
  419.             raise;
  420.       end;
  421.  
  422.    exception
  423.       when Tasking_Error | Program_Error =>
  424.          raise;
  425.  
  426.       when others =>
  427.          raise Program_Error;
  428.    end Reference;
  429.  
  430.    ------------------
  431.    -- Reinitialize --
  432.    ------------------
  433.  
  434.    procedure Reinitialize
  435.      (T : Task_Identification.Task_Id := Task_Identification.Current_Task)
  436.    is
  437.       Lock_Result : Boolean;
  438.       TT : Task_ID := To_Task_ID (T);
  439.  
  440.    begin
  441.       if TT = Null_ID then
  442.          raise Program_Error;
  443.       end if;
  444.  
  445.       if TT.Stage = Terminated then
  446.          raise Tasking_Error;
  447.       end if;
  448.  
  449.       if Local.Index = 0 then
  450.          declare
  451.             P, Q : Access_Node;
  452.             W    : Access_Wrapper;
  453.  
  454.          begin
  455.             Defer_Abortion; Write_Lock (TT.L, Lock_Result);
  456.  
  457.             Q := To_Access_Node (TT.Indirect_Attributes);
  458.             while Q /= null loop
  459. --  Gigi bug: ???
  460. --               if Q.Instance = Local'Unchecked_Access then
  461.                if Q.Instance = Access_Instance'(Local'Unchecked_Access) then
  462.                   if P = null then
  463.                      TT.Indirect_Attributes := To_Access_Address (Q.Next);
  464.  
  465.                   else
  466.                      P.Next := Q.Next;
  467.                   end if;
  468.  
  469.                   W := To_Access_Wrapper (Q.Wrapper);
  470.                   Free (W);
  471.                   Unlock (TT.L);
  472.                   Undefer_Abortion;
  473.                   return;
  474.                end if;
  475.  
  476.                P := Q;
  477.                Q := Q.Next;
  478.             end loop;
  479.  
  480.             Unlock (TT.L);
  481.             Undefer_Abortion;
  482.  
  483.          exception
  484.             when others =>
  485.                Unlock (TT.L);
  486.                Undefer_Abortion;
  487.          end;
  488.  
  489.       else
  490.          Set_Value (Initial_Value, T);
  491.       end if;
  492.  
  493.    exception
  494.       when Tasking_Error | Program_Error =>
  495.          raise;
  496.  
  497.       when others =>
  498.          raise Program_Error;
  499.    end Reinitialize;
  500.  
  501.    ---------------
  502.    -- Set_Value --
  503.    ---------------
  504.  
  505.    procedure Set_Value
  506.      (Val : Attribute;
  507.       T   : Task_Identification.Task_Id := Task_Identification.Current_Task)
  508.    is
  509.       Lock_Result : Boolean;
  510.       TT          : Task_ID := To_Task_ID (T);
  511.  
  512.    begin
  513.       if TT = Null_ID then
  514.          raise Program_Error;
  515.       end if;
  516.  
  517.       if TT.Stage = Terminated then
  518.          raise Tasking_Error;
  519.       end if;
  520.  
  521.       begin
  522.          Defer_Abortion;
  523.          Write_Lock (TT.L, Lock_Result);
  524.  
  525.          if Local.Index /= 0 then
  526.             To_Attribute_Handle
  527.                (TT.Direct_Attributes (Local.Index)'Access).all := Val;
  528.             Unlock (TT.L);
  529.             Undefer_Abortion;
  530.             return;
  531.  
  532.          else
  533.             declare
  534.                P : Access_Node := To_Access_Node (TT.Indirect_Attributes);
  535.                W : Access_Wrapper;
  536.  
  537.             begin
  538.                while P /= null loop
  539.  
  540. --  Gigi bug: ???
  541. --                  if P.Instance = Local'Unchecked_Access then
  542.  
  543.                   if P.Instance = Access_Instance'(Local'Unchecked_Access) then
  544.                      To_Access_Wrapper (P.Wrapper).Value := Val;
  545.                      Unlock (TT.L);
  546.                      Undefer_Abortion;
  547.                      return;
  548.                   end if;
  549.  
  550.                   P := P.Next;
  551.                end loop;
  552.  
  553.                W := new Wrapper'
  554.                  ((null, Local'Unchecked_Access, null), Val);
  555.  
  556.                P := W.Noed'Unchecked_Access;
  557.                P.Wrapper := To_Access_Dummy_Wrapper (W);
  558.                P.Next := To_Access_Node (TT.Indirect_Attributes);
  559.                TT.Indirect_Attributes := To_Access_Address (P);
  560.             end;
  561.          end if;
  562.  
  563.          Unlock (TT.L);
  564.          Undefer_Abortion;
  565.  
  566.       exception
  567.          when others =>
  568.             Unlock (TT.L);
  569.             Undefer_Abortion;
  570.             raise;
  571.       end;
  572.  
  573.       return;
  574.  
  575.    exception
  576.       when Tasking_Error | Program_Error =>
  577.          raise;
  578.  
  579.       when others =>
  580.          raise Program_Error;
  581.  
  582.    end Set_Value;
  583.  
  584.    -----------
  585.    -- Value --
  586.    -----------
  587.  
  588.    function Value
  589.      (T    : Task_Identification.Task_Id := Task_Identification.Current_Task)
  590.       return Attribute
  591.    is
  592.       Lock_Result : Boolean;
  593.       Result      : Attribute;
  594.       TT          : Task_ID := To_Task_ID (T);
  595.  
  596.    begin
  597.       if TT = Null_ID then
  598.          raise Program_Error;
  599.       end if;
  600.  
  601.       if TT.Stage = Terminated then
  602.          raise Tasking_Error;
  603.       end if;
  604.  
  605.       begin
  606.          if Local.Index /= 0 then
  607.             Result := To_Attribute_Handle
  608.                (TT.Direct_Attributes (Local.Index)'Access).all;
  609.  
  610.          else
  611.             declare
  612.                P : Access_Node;
  613.  
  614.             begin
  615.                Defer_Abortion; Write_Lock (TT.L, Lock_Result);
  616.                P := To_Access_Node (TT.Indirect_Attributes);
  617.                while P /= null loop
  618.  
  619. --  Gigi bug: ???
  620. --                  if P.Instance = Local'Unchecked_Access then
  621.  
  622.                   if P.Instance = Access_Instance'(Local'Unchecked_Access) then
  623.                      Unlock (TT.L);
  624.                      Undefer_Abortion;
  625.                      return To_Access_Wrapper (P.Wrapper).Value;
  626.                   end if;
  627.  
  628.                   P := P.Next;
  629.                end loop;
  630.  
  631.                Result := Initial_Value;
  632.                Unlock (TT.L);
  633.                Undefer_Abortion;
  634.  
  635.             exception
  636.                when others =>
  637.                   Unlock (TT.L);
  638.                   Undefer_Abortion;
  639.                   raise;
  640.             end;
  641.          end if;
  642.  
  643.          return Result;
  644.       end;
  645.  
  646.    exception
  647.       when Tasking_Error | Program_Error =>
  648.          raise;
  649.  
  650.       when others =>
  651.          raise Program_Error;
  652.    end Value;
  653.  
  654. --  Start of elaboration code for package Ada.Task_Attributes
  655.  
  656. begin
  657.    Local.Deallocate := To_Lib_Level_Deallocator (Deallocate'Access);
  658.  
  659.    declare
  660.       Lock_Result : Boolean;
  661.       Two_To_J    : Direct_Index_Vector;
  662.  
  663.    begin
  664.       Defer_Abortion;
  665.       Write_Lock (All_Attrs_L, Lock_Result);
  666.       pragma Assert
  667.         (not Lock_Result or else
  668.          System.Tasking.Utilities.Runtime_Assert_Shutdown ("Locking error"));
  669.  
  670.       --  Add this instantiation to the list of all instantiations.
  671.  
  672.       Local.Next := System.Tasking.Task_Attributes.All_Attributes;
  673.       System.Tasking.Task_Attributes.All_Attributes :=
  674.         Local'Unchecked_Access;
  675.  
  676.       --  Try to find space for the attribute in the TCB.
  677.  
  678.       Local.Index := 0;
  679.       Two_To_J := 2 ** Direct_Index'First;
  680.       if Attribute'Size <= System.Address'Size then
  681.          for J in Direct_Index loop
  682.             if (Two_To_J and In_Use) /= 0 then
  683.  
  684.                --  Reserve location J for this attribute
  685.  
  686.                In_Use := In_Use or Two_To_J;
  687.                Local.Index := J;
  688.                To_Attribute_Handle (Local.Initial_Value'Access).all :=
  689.                                                                Initial_Value;
  690.                exit;
  691.             end if;
  692.  
  693.             Two_To_J := Two_To_J * 2;
  694.          end loop;
  695.       end if;
  696.  
  697.       --  Need protection of All_Tasks_L for updating links to
  698.       --  per-task initialization and finalization routines,
  699.       --  in case some task is being created or terminated concurrently.
  700.  
  701.       Write_Lock
  702.          (System.Tasking.Initialization.All_Tasks_L, Lock_Result);
  703.  
  704.       pragma Assert
  705.         (not Lock_Result or else
  706.          System.Tasking.Utilities.Runtime_Assert_Shutdown
  707.          ("Error in locking"));
  708.  
  709.       --  Attribute goes directly in the TCB
  710.  
  711.       if Local.Index /= 0 then
  712.  
  713.          --  Replace stub for initialization routine
  714.          --  that is called at task creation.
  715.  
  716.          System.Tasking.Initialization.Initialize_Attributes_Link :=
  717.            System.Tasking.Task_Attributes.Initialize_Attributes'Access;
  718.  
  719.          --  Initialize the attribute, for all tasks.
  720.  
  721.          declare
  722.             C : System.Tasking.Task_ID :=
  723.                   System.Tasking.Initialization.All_Tasks_List;
  724.             P : Access_Node;
  725.  
  726.          begin
  727.             while C /= null loop
  728.                Write_Lock (C.L, Lock_Result);
  729.                pragma Assert
  730.                  (not Lock_Result or else
  731.                    System.Tasking.Utilities.Runtime_Assert_Shutdown
  732.                    ("Locking error"));
  733.                C.Direct_Attributes (Local.Index) :=
  734.                   System.Storage_Elements.To_Address (Local.Initial_Value);
  735.                Unlock (C.L);
  736.                C := C.All_Tasks_Link;
  737.             end loop;
  738.          end;
  739.  
  740.       --  Attribute goes into a node onto a linked list
  741.  
  742.       else
  743.          --  Replace stub for finalization routine
  744.          --  that is called at task termination.
  745.  
  746.          System.Tasking.Initialization.Finalize_Attributes_Link :=
  747.            System.Tasking.Task_Attributes.Finalize_Attributes'Access;
  748.  
  749.       end if;
  750.  
  751.       Unlock (System.Tasking.Initialization.All_Tasks_L);
  752.       Unlock (All_Attrs_L);
  753.       Undefer_Abortion;
  754.  
  755.    exception
  756.       when others => null;
  757.          pragma Assert
  758.            (System.Tasking.Utilities.Runtime_Assert_Shutdown
  759.              ("Exception in task attribute initializer"));
  760.  
  761.          --  If we later decide to allow exceptions to propagate,
  762.          --  we need to not only release locks and undefer abortion,
  763.          --  we also need to undo any initializations that
  764.          --  succeeded up to this point, or we will risk a
  765.          --  dangling reference when the task terminates.
  766.    end;
  767.  
  768. end Ada.Task_Attributes;
  769.